package cn.dm.high.chain;

import com.lmax.disruptor.BusySpinWaitStrategy;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Disruptor串并行操作总结：
 * 链式编程(打点调用)是串行
 * 如disruptor.handleEventsWith(new Handler1()).handleEventsWith(new Handler2()).handleEventsWith(new Handler3());
 * <p>
 * 链中有多个参数时是并行
 * 如disruptor.handleEventsWith(new Handler1(), new Handler2(), new Handler3());
 * <p>
 * 由上面两点可知,可组合为多边形操作
 * 如disruptor.handleEventsWith(new Handler1(), new Handler2()).handleEventsWith(new Handler3());
 */
public class Main {


    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {

        //构建一个线程池用于提交任务
        ExecutorService es1 = Executors.newFixedThreadPool(1);
        // 案例中五个Handler,故设置到Disruptor中的线程池最少5个,否则运行结果达不到预期效果
//        ExecutorService es2 = Executors.newFixedThreadPool(4);
        ExecutorService es2 = Executors.newFixedThreadPool(5);

        //1 构建Disruptor
        Disruptor<Trade> disruptor = new Disruptor<Trade>(
                new EventFactory<Trade>() {
                    public Trade newInstance() {
                        return new Trade();
                    }
                },
                1024 * 1024,
                es2,
                ProducerType.SINGLE,
                new BusySpinWaitStrategy());


        //2 把消费者设置到Disruptor中 handleEventsWith

        /**
         * 2.1 串行操作
         */
//        disruptor
//                .handleEventsWith(new Handler1())
//                .handleEventsWith(new Handler2())
//                .handleEventsWith(new Handler3());
        /**
         * 预期结果:串行,故先打印Handler1的SET NAME,再打印Handler2的SET ID,然后打印Handler3的输出内容
         *
         * 实际结果如下
         * handler 1 : SET NAME
         * handler 2 : SET ID
         * handler 3 : NAME: H1, ID: 3afba758-71f3-477e-a8ba-8b43fe52d06d, PRICE: 4649.883787727962 INSTANCE : cn.dm.high.chain.Trade@cb88e21
         * 总耗时: 3159
         *
         * 顺序与预期结果一致!
         */


        /**
         * 2.2 并行操作: 可以有两种方式去进行
         * 1)handleEventsWith方法 分别进行调用
         * 2)handleEventsWith方法 添加多个handler实现即可
         */
        // 1)
//        disruptor.handleEventsWith(new Handler1());
//        disruptor.handleEventsWith(new Handler2());
//        disruptor.handleEventsWith(new Handler3());
        // 2)
//        disruptor.handleEventsWith(new Handler1(), new Handler2(), new Handler3());
        /**
         * 实际结果
         * handler 1 : SET NAME
         * handler 2 : SET ID
         * handler 3 : NAME: null, ID: null, PRICE: 2651.9597081249717 INSTANCE : cn.dm.high.chain.Trade@200e9a5f
         * 总耗时: 2124
         *
         * 说明
         * Handler1和Handler2都是先休眠再赋值,故并行操作时导致Handler3打印的name和id属性均为null
         */


        /**
         * 2.3 多边形操作一:菱形操作(即四边形操作)
         * 1)把上面的串行行操作进行组合,达到多边形操作的效果
         * 2)获取EventHandlerGroup对象,该对象内并行,然后使用then方法进行串行
         */
        // 1)
//        disruptor.handleEventsWith(new Handler1(), new Handler2()).handleEventsWith(new Handler3());
        // 2)
//        EventHandlerGroup<Trade> ehGroup = disruptor.handleEventsWith(new Handler1(), new Handler2());
//        ehGroup.then(new Handler3());
        /**
         * 实际结果
         * handler 2 : SET ID
         * handler 1 : SET NAME
         * handler 3 : NAME: H1, ID: 223216c8-d4ed-488d-b096-f665e0597302, PRICE: 528.380029431877 INSTANCE : cn.dm.high.chain.Trade@78eadd8c
         * 总耗时: 2154
         *
         * 分析：Handler1和Handler2并行操作进行赋值,然后Handler3进行打印
         * 注意：此时Handler1和Handler2并行,然后与Handler3串行.注意结果name和id属性均已经赋值,与上面案例对比
         */

        /**
         * 2.4 多边形操作二:六边形操作
         */
        Handler1 h1 = new Handler1();
        Handler2 h2 = new Handler2();
        Handler3 h3 = new Handler3();
        Handler4 h4 = new Handler4();
        Handler5 h5 = new Handler5();
        disruptor.handleEventsWith(h1, h4); // h1和h4并行
        disruptor.after(h1).handleEventsWith(h2); // h1和h2串行
        disruptor.after(h4).handleEventsWith(h5); // h4和h5串行
        disruptor.after(h2, h5).handleEventsWith(h3); // h2和h5完成后结果汇总到h3
        /**
         * 结果
         * handler 1 : SET NAME
         * handler 4 : SET PRICE
         * handler 2 : SET ID
         * handler 5 : GET PRICE: 66.66
         * handler 3 : NAME: H1, ID: c985bbd8-f799-442f-b1e6-16aa763d27c6, PRICE: 88.88 INSTANCE : cn.dm.high.chain.Trade@39d5023b
         * 总耗时: 3138
         *
         * 由上面打印可知,先执行的handler1和handler4,然后执行的handler2和handler5,最后执行handler3
         * 且handler4和handler5一定是串行的,因为最后结果是88.88(故肯定是先设置为66.66加22.22后才变为88.88)
         */


        //3 启动disruptor
        RingBuffer<Trade> ringBuffer = disruptor.start();

        CountDownLatch latch = new CountDownLatch(1);

        long beginTime = System.currentTimeMillis();
        es1.submit(new TradePublisher(latch, disruptor));
        latch.await();    //进行向下
        disruptor.shutdown();
        es1.shutdown();
        es2.shutdown();
        long endTime = System.currentTimeMillis();
        System.err.println("总耗时: " + (endTime - beginTime) + "ms");
    }
}
